package com.aiolos.springboot.stepbystep.service.impl;

import com.aiolos.springboot.stepbystep.dao.AyUserDao;
import com.aiolos.springboot.stepbystep.error.BusinessException;
import com.aiolos.springboot.stepbystep.model.AyPermission;
import com.aiolos.springboot.stepbystep.model.AyRole;
import com.aiolos.springboot.stepbystep.model.AyUser;
import com.aiolos.springboot.stepbystep.repository.AyRoleRepository;
import com.aiolos.springboot.stepbystep.repository.AyUserRepository;
import com.aiolos.springboot.stepbystep.service.IAyUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Future;

@Service
public class AyUserServiceImpl implements IAyUserService {

    @Resource
    private AyUserRepository ayUserRepository;

    @Resource
    private AyRoleRepository ayRoleRepository;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private AyUserDao ayUserDao;

    Logger logger = LoggerFactory.getLogger(this.getClass());

    //存放到Redis中的用户数据的变量名，后期应存放到常量类中
    private static final String REDIS_ALL_USER = "ALL_USER_LIST";

    @Override
    public AyUser findByNameAndPassword(String name, String password) {
        return ayUserDao.findByNameAndPassword(name,password);
    }

    /**
     * 测试Retry重试机制
     * 在方法中抛出BusinessException异常，触发重试机制
     * @Retryable()注解：用于标记该方法可执行重试
     *      value属性表示当出现哪些异常时触发重试机制；
     *      maxAttempts表示最大重试次数，默认为3；
     *      delay表示重试的延迟时间；
     *      multiplier表示上一次延时时间是这一次的倍数；
     *
     * @param name
     * @param password
     * @return
     */
    @Override
    @Retryable(value = {BusinessException.class},maxAttempts = 5,
            backoff = @Backoff(delay = 5000,multiplier = 2))
    public AyUser findByNameAndPasswordRetry(String name, String password) {
        logger.info("[findByNameAndPasswordRetry]  方法失败，进行重试...");
        throw new BusinessException("发生业务异常，准备重试...");
    }


    @Override
    public AyUser findById(Integer id) {
        //一、直接从数据库中查询方式
        //return ayUserRepository.findById(id).get();

        //二、使用Redis缓存的查询方式
        //1. 首先从Redis中查询，如果找到则直接返回结果即可
        List<AyUser> ayUserList = redisTemplate.opsForList().range(REDIS_ALL_USER,0,-1);
        for(AyUser user : ayUserList){
            if(id.equals(user.getId())){
                return user;
            }
        }

        //2. 如果Redis中不存在，则到数据库中查询
        AyUser user = ayUserRepository.findById(id).get();

        //3. 如果数据库中存在，则将数据更新到Redis中，同时返回结果；
        if(user!=null){
            redisTemplate.opsForList().leftPush(REDIS_ALL_USER,user);
            return user;
        }

        //4. 如果数据库中不存在则返回null
        return null;
    }

    @Override
    public List<AyUser> findAll() {
        try{
            logger.info("开始做任务");
            long start = System.currentTimeMillis();
            List<AyUser> ayUserList = ayUserRepository.findAll();
            long end = System.currentTimeMillis();
            logger.info("完成任务，耗时：" + (end - start) + "毫秒");
            return ayUserList;
        }catch (Exception e){
            logger.error("method [findAll()] error",e);
            return Collections.EMPTY_LIST;
        }
    }

    /**
     * 异步调用
     * @return
     */
    @Override
    @Async
    public Future<List<AyUser>> findAsynAll() {
        try{
            logger.info("开始做任务");
            long start = System.currentTimeMillis();
            List<AyUser> ayUserList = ayUserRepository.findAll();
            long end = System.currentTimeMillis();
            logger.info("完成任务，耗时：" + (end - start) + "毫秒");
            return new AsyncResult<List<AyUser>>(ayUserList) ;
        }catch (Exception e){
            logger.error("method [findAsynAll()] error",e);
            return new AsyncResult<List<AyUser>>(null);
        }
    }

    //注解在方法上
    @Transactional
    @Override
    public AyUser save(AyUser ayUser) {
        AyUser saveUser  = ayUserRepository.save(ayUser);
        //模拟出现空指针异常
        String error = null;
        error.split("/");
        return saveUser;
    }

    @Override
    public void delete(Integer id) {
        ayUserRepository.deleteById(id);
    }

    @Override
    public Page<AyUser> findAll(Pageable pageable) {
        return ayUserRepository.findAll(pageable);
    }

    /**
     * 添加角色
     * @param map
     * @return
     */
    @Override
    public AyRole addRole(Map<String, Object> map) {
        AyUser user = ayUserRepository.getOne(Integer.valueOf(map.get("id").toString()));
        AyRole role = new AyRole();
        role.setRole_name(map.get("role_name").toString());
        role.setAyUser(user);
        AyPermission permission1 = new AyPermission();
        permission1.setPermission_name("create");
        permission1.setAyRole(role);
        AyPermission permission2 = new AyPermission();
        permission2.setPermission_name("update");
        permission2.setAyRole(role);
        List<AyPermission> permissions = new ArrayList<AyPermission>();
        permissions.add(permission1);
        permissions.add(permission2);
        role.setPermissions(permissions);
        ayRoleRepository.save(role);
        return role;
    }

    @Override
    public List<AyUser> findByNameLike(String name) {
        return ayUserRepository.findByNameLike(name);
    }

    @Override
    public AyUser findByName(String name) {
        return ayUserRepository.findByName(name);
    }

    @Override
    public List<AyUser> findByIdIn(Collection<Integer> ids){
        return ayUserRepository.findByIdIn(ids);
    }
}
